// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "front/front_interface.h"
using namespace std;
using namespace ppspeech;

//构造函数
FrontEngineInterface::FrontEngineInterface(const string fInDictFolderPath, const string fInUserContextFilepath, const bool fInUpdateBiasfileFlag):
	mDbDictPath(fInDictFolderPath + "phoneme/phoneme.db"),	mDictionary(mDbDictPath),
	mDbBiasDictPath(fInDictFolderPath + "phoneme/phonemeBias.db"),	mDictionaryBias(mDbBiasDictPath)
{
	mFrontInitialedFlag = false;

	if(fInUpdateBiasfileFlag) {
		FrontUpdateBiasFile(fInUserContextFilepath, fInDictFolderPath);
	}

	TextNormalizer();

	//结巴分词
	const string jieba_folder_path = fInDictFolderPath + "jieba/";

	mFrontJieba = new cppjieba::Jieba(	(jieba_folder_path + "jieba.dict.utf8"),
										(jieba_folder_path + "hmm_model.utf8"),
										(jieba_folder_path + "user.dict.utf8"),
										(jieba_folder_path + "idf.utf8"),
										(jieba_folder_path + "stop_words.utf8")	);
}


bool FrontEngineInterface::FrontEngineLoadPhonemeMap(const string fInModelPhoneidxFilepath)
{
	// 读取音素表（音素到音素id的映射）
	if (false == FrontPinyinMap(fInModelPhoneidxFilepath, &mPhonemeIndexMap)) {
		printf("ERROR: Frontend: Genarate phone2id dict failed\n");
		return false;
	}

	mFrontInitialedFlag = true;
	return true;
}


//析构函数
FrontEngineInterface::~FrontEngineInterface()
{
	delete mFrontJieba;
	mFrontInitialedFlag = false;
}

//返回前端初始化状态
bool FrontEngineInterface::FrontGetInitialedFlag()
{
	return mFrontInitialedFlag;
}


int FrontEngineInterface::GetSegResult(
	vector<pair<string, string>>& seg,
	vector<string> *seg_words) {
	vector<pair<string, string>>::iterator iter;
	for (iter = seg.begin(); iter != seg.end(); iter++) {
		seg_words->push_back((*iter).first);
	}
	return 0;
}

// 判断词是否是叠词
bool FrontEngineInterface::IsReduplication(const string &word) {
	bool flags = false;
	wstring word_wstr = ppspeech::utf8string2wstring(word);
	int len = word_wstr.length();
	if (len == 2 && word_wstr[0] == word_wstr[1]) {
		flags = true;
	}
	return flags;
}

// 获取每个字词的声母和韵母列表， word_initials 为声母列表，word_finals 为韵母列表
int FrontEngineInterface::GetInitialsFinals(const string &word, vector<string> *word_initials, vector<string> *word_finals)
{
	string t_phoneme_str = "";
	//获取字词对应的音素

	if( utf8string2wstring(word).length() == 1 )
	{
		//中文单字查询。如果热词词典找不到，则找常规词典。
		if( "" != (t_phoneme_str = mDictionaryBias.find_sqlite_dict(DatabaseDictTableZhChar, word) )
			 || "" != (t_phoneme_str = mDictionary.find_sqlite_dict(DatabaseDictTableZhChar, word) )  )
		{
		}
		else {
			t_phoneme_str = "sp";
		}
	}
	else
	{
		//先热词查找
		if( "" != (t_phoneme_str = mDictionaryBias.find_sqlite_dict(DatabaseDictTableZhPhrase, word)) )	//如果热词词典找不到，则找常规词典。
		{
		}
		else if( "" == (t_phoneme_str = mDictionary.find_sqlite_dict(DatabaseDictTableZhPhrase, word)) )	//如果中文词组找不到，则拆分找中文单字。
		{
			bool tFirstFlag = true;
			for(string w : FrontUtf8WordSplit(word)) {
				string t = "";

				//中文单字查询。如果热词词典找不到，则找常规词典。
				if( "" != (t = mDictionaryBias.find_sqlite_dict(DatabaseDictTableZhChar, w) )
					 || "" != (t = mDictionary.find_sqlite_dict(DatabaseDictTableZhChar, w) )  )
				{
					t_phoneme_str += (tFirstFlag?"":" ") + t;
					tFirstFlag = false;
				}
			}
		}
	}

	vector<string> phone_vec = absl::StrSplit(t_phoneme_str, " ");

	//获取韵母，每个字的音素有1或者2个，start为单个字音素的起始位置。
	int start = 0;
	while (start < phone_vec.size())
	{
		if (phone_vec[start] == "") {		//忽略字典查不到的情况
			start += 1;
		}
		else if (phone_vec[start] == "sp" || phone_vec[start] == "sp0") {
			start += 1;
		}
		else if (isdigit(phone_vec[start].back()) == 0 ||
				static_cast<int>(phone_vec[start].back()) == 48) {
			word_initials->push_back(phone_vec[start]);
			word_finals->push_back(phone_vec[start + 1]);
			start += 2;
		}
		else {
			word_initials->push_back("");
			word_finals->push_back(phone_vec[start]);
			start += 1;
		}
	}

	assert(word_finals->size() == word_initials->size());

	return 0;
}

// 获取每个字词的韵母列表
int FrontEngineInterface::GetFinals(const string &word,
									vector<string> *word_finals) {
	vector<string> word_initials;
	if (0 != GetInitialsFinals(word, &word_initials, word_finals)) {
		printf("ERROR: Frontend: Failed to get word finals\n");
		return -1;
	}

	return 0;
}

int FrontEngineInterface::Word2WordVec(const string &word,
									vector<wstring> *wordvec) {
	wstring word_wstr = ppspeech::utf8string2wstring(word);
	for (int i = 0; i < word_wstr.length(); i++) {
		wstring word_sigle(1, word_wstr[i]);
		wordvec->push_back(word_sigle);
	}
	return 0;
}

// yuantian01解释：把一个词再进行分词找到。例子：小雨伞 --> 小 雨伞 或者 小雨 伞
int FrontEngineInterface::SplitWord(const string &word, vector<string> *new_word_vec)
{
	vector<string> word_vec;
	string second_subword;
	mFrontJieba->CutForSearch(word, word_vec);
	// 升序
	sort(word_vec.begin(), word_vec.end(), [](string a, string b) { return a.size() > b.size(); });
	string first_subword = word_vec[0];  // 提取长度最短的字符串
	int first_begin_idx = word.find_first_of(first_subword);
	if (first_begin_idx == 0) {
		second_subword = word.substr(first_subword.length());
		new_word_vec->push_back(first_subword);
		new_word_vec->push_back(second_subword);
	}
	else {
		second_subword = word.substr(0, word.length() - first_subword.length());
		new_word_vec->push_back(second_subword);
		new_word_vec->push_back(first_subword);
	}

	return 0;
}


// example: 不 一起 --> 不一起
vector<pair<string, string>> FrontEngineInterface::MergeBu(
	vector<pair<string, string>>& seg_result) {
	vector<pair<string, string>> result;
	string word;
	string pos;
	string last_word = "";

	for (int i = 0; i < seg_result.size(); i++) {
		word = get<0>(seg_result[i]);
		pos = get<1>(seg_result[i]);
		if (last_word == "不") {
			if(pos == "eng" || word == " " || pos == "x") {		//不care、不 OK
				result.push_back(make_pair(last_word, "d"));
			}
			else {
				word = last_word + word;
			}
		}
		if (word != "不") {
			result.push_back(make_pair(word, pos));
		}
		last_word = word;
	}

	if (last_word == "不") {
		result.push_back(make_pair(last_word, "d"));
		last_word = "";
	}

	return result;
}

vector<pair<string, string>> FrontEngineInterface::Mergeyi(vector<pair<string, string>>& seg_result)
{
	vector<pair<string, string>> result_temp;
	string word;
	string pos;
	// function 1  example: 听 一 听 --> 听一听
	for (int i = 0; i < seg_result.size(); i++) {
		word = get<0>(seg_result[i]);
		pos = get<1>(seg_result[i]);

		if ((i - 1 >= 0) && (word == "一") && (i + 1 < seg_result.size()) &&
			(get<0>(seg_result[i - 1]) ==
			get<0>(seg_result[i + 1])) &&
			get<1>(seg_result[i - 1]) == "v") {
			get<0>(result_temp[i - 1]) =
				get<0>(result_temp[i - 1]) + "一" +
				get<0>(result_temp[i - 1]);
		} else {
			if ((i - 2 >= 0) && (get<0>(seg_result[i - 1]) == "一") &&
				(get<0>(seg_result[i - 2]) == word) && (pos == "v")) {
				continue;
			} else {
				result_temp.push_back(make_pair(word, pos));
			}
		}
	}

	// function 2  example: 一 你 -->  一你
	vector<pair<string, string>> result = {};
	for (int j = 0; j < result_temp.size(); j++) {
		word = get<0>(result_temp[j]);
		pos = get<1>(result_temp[j]);
		if ((result.size() != 0) && (result.back().first == "一") && (pos != "x" && pos != "eng")) {
			result.back().first = result.back().first + word;
		} else {
			result.push_back(make_pair(word, pos));
		}
	}

	return result;
}

// example: 你 你 --> 你你
vector<pair<string, string>>
FrontEngineInterface::MergeReduplication(
	vector<pair<string, string>>& seg_result) {
	vector<pair<string, string>> result;
	string word;
	string pos;

	for (int i = 0; i < seg_result.size(); i++) {
		word = get<0>(seg_result[i]);
		pos = get<1>(seg_result[i]);
		if ((result.size() != 0) && (word == result.back().first) && (word != "幺")) {
			result.back().first =
				result.back().first + get<0>(seg_result[i]);
		} else {
			result.push_back(make_pair(word, pos));
		}
	}

	return result;
}

// example: 吃饭 儿 --> 吃饭儿
vector<pair<string, string>> FrontEngineInterface::MergeEr(vector<pair<string, string>>& seg_result)
{
	vector<pair<string, string>> result;
	string word;
	string pos;

	for (int i = 0; i < seg_result.size(); i++) {
		word = get<0>(seg_result[i]);
		pos = get<1>(seg_result[i]);
		if ((i - 1 >= 0) && (word == "儿")) {
			result.back().first = result.back().first + get<0>(seg_result[i]);
		}
		else {
			result.push_back(make_pair(word, pos));
		}
	}

	return result;
}


bool FrontEngineInterface::FrontModifyYiSandhi(const string& fcaInWord, vector<string>& fcaInFinals)
{
	wstring yi = L"一";
	vector<wstring> wordvec;
	// 一个词转成向量形式
	if (0 != Word2WordVec(fcaInWord, &wordvec)) {
		printf("ERROR: Frontend: Failed to get word vector\n");
		return false;
	}

	bool only_yi = true;
	for(wstring w : wordvec) {
		if(w != yi) {
			only_yi = false;
			break;
		}
	}
	if(only_yi) {	//全是"一"
		return true;
	}

	//情况1："一" in number sequences, e.g. 一零零, 二一零
	wstring num_wstr = L"零一二三四六七八九";
	wstring word_wstr = ppspeech::utf8string2wstring(fcaInWord);

	if (wordvec[0] == L"第" && wordvec[1] == yi) {  //以第一位开始
		fcaInFinals[1] = fcaInFinals[1].replace(fcaInFinals[1].length() - 1, 1, "1");
		return true;
	}
	else if (word_wstr.find(yi) != word_wstr.npos && wordvec.back() != yi) {
		bool tAllNumFlag = true;
		for (int j = 0; j < wordvec.size(); j++) {
			if (num_wstr.find(wordvec[j]) == num_wstr.npos) {
				tAllNumFlag = false;
				break;
			}
		}
		if (tAllNumFlag) {
			return true;
		}
	}
	else if (wordvec.size() == 3 && wordvec[1] == yi && wordvec[0] == wordvec[2]) {
		// "一" between reduplication words shold be yi5, e.g. 看一看
		fcaInFinals[1] = fcaInFinals[1].replace(fcaInFinals[1].length() - 1, 1, "5");
		return true;
	}


	for (int i = 0; i < wordvec.size(); i++) {
		if (wordvec[i] == yi && i + 1 < wordvec.size()) {
			if (absl::EndsWith(fcaInFinals[i + 1], "4") == true) {
				// "一" before tone4 should be yi2, e.g. 一段
				if(i>0 && wordvec[i-1] == L"十") {
				}
				else {
					if(wordvec[i+1] != L"是" && wordvec[i+1] != L"队") {
						fcaInFinals[i] = fcaInFinals[i].replace(fcaInFinals[i].length() - 1, 1, "2");
					}
				}
			}
			else {
				// "一" before non-tone4 should be yi4, e.g. 一天
				if(wordvec[i+1] != L"一" && wordvec[i+1] != L"十" && wordvec[i+1] != L"等"
					 && wordvec[i+1] != L"楼" && wordvec[i+1] != L"层"		// && wordvec[i+1] != L"点"
					 && wordvec[i+1] != L"年" && wordvec[i+1] != L"月"
					 && wordvec[i+1] != L"加" && wordvec[i+1] != L"减" && wordvec[i+1] != L"乘" && wordvec[i+1] != L"除")
				{
					fcaInFinals[i] = fcaInFinals[i].replace(fcaInFinals[i].length() - 1, 1, "4");
				}
			}
		}
	}
	return true;
}
